package fr.umlv.ig.metroApplication;


import java.awt.BorderLayout;
import java.awt.Component;
import java.awt.Container;
import java.awt.Dimension;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.io.File;
import java.io.IOException;
import java.util.Random;

import javax.swing.JButton;
import javax.swing.JFileChooser;
import javax.swing.JFrame;
import javax.swing.JPanel;
import javax.swing.JTabbedPane;
import javax.swing.JToolBar;
import javax.swing.Timer;
import javax.swing.UIManager;
import javax.swing.UnsupportedLookAndFeelException;
import javax.xml.parsers.ParserConfigurationException;

import org.xml.sax.SAXException;

import fr.umlv.ig.extraWindows.AboutWindow;
import fr.umlv.ig.extraWindows.ConfigurationWindow;
import fr.umlv.ig.extraWindows.ExitApplicationWindow;
import fr.umlv.ig.listenerFactory.ApplicationListenerFactory;
import fr.umlv.ig.metroFactory.GraphicFactory;
import fr.umlv.ig.metroView.confView.TabbedConfView;
import fr.umlv.ig.metroView.map.MetroMap;
import fr.umlv.ig.model.Itinerary;
import fr.umlv.ig.model.Line;
import fr.umlv.ig.model.MetroModelImpl;
import fr.umlv.ig.model.Train;
import fr.umlv.ig.xml.MetroModelFactory;
import fr.umlv.ig.xml.SaveXml;

/**
 * The Application of the project. 
 * @author jenseric
 * @author william
 *
 */
public class MetroApplication {

	/**Frame of the application*/
	private final JFrame frame = new JFrame("Jack BeauHeur");
	
	/**Model used for the application*/
	private MetroModelImpl model;
	
	/**
	 * generator use for generate random itinerary
	 */
	private static final Random generator = new Random();
	
//	/**
//	 * ActionListener which is showing a {@link ConfigurationWindow} to configure lines
//	 */
//	private final ActionListener toolWindow = new ActionListener() {
//		private ConfigurationWindow cw;
//		@Override
//
//		public void actionPerformed(ActionEvent e) {
//			if(cw == null) {
//				cw = new ConfigurationWindow(frame, "Line configuration", model);
//			}
//			cw.start();
//		}
//	};
	
	/**
	 * ActionListener which is opening a JFileChooser for save Configuration
	 */
	private final ActionListener saveWindow = new ActionListener() {
		@Override

		public void actionPerformed(ActionEvent e) {
			SaveXml saveXML;
			try {
				saveXML = new SaveXml(model, saveConfig());
				saveXML.save();
			} catch (IOException e1) {
				e1.printStackTrace();
			}
			
		}
	};
	
	
	
	/**
	 * ActionListener which is showing a {@link AboutWindow} to configure lines
	 */
	private final ActionListener aboutWindow = new ActionListener() {
		AboutWindow aw;
		@Override

		public void actionPerformed(ActionEvent e) {
			if(aw==null) {
				aw = new AboutWindow(frame);
			}
			aw.start();
		}
	};
	
	/**
	 * ActionListener that exit the program
	 */
	private final ActionListener exitProgram = new ActionListener() {
		ExitApplicationWindow eaw;
		@Override

		public void actionPerformed(ActionEvent e) {
			if(eaw==null) {
				eaw = new ExitApplicationWindow(frame, "Exit Window");
			}
			eaw.start();
		}
	};

	private final ActionListener addRandomTrains = new ActionListener() {
		private Timer timer;
		private ActionListener radomTrains = new ActionListener() {

			@Override
			public void actionPerformed(ActionEvent e) {
				for(int i=0; i<model.getCountLine(); i++) {
					Line line = model.getLine(i);
					int random = generator.nextInt(model.getCountItinerary(line));
					Itinerary itinerary = model.getItinerary(line, random);
					Train train = new Train(itinerary);
					model.addTrain(line, train);
				}
			}
		};

		@Override
		public void actionPerformed(ActionEvent e) {
			if(timer == null)
				timer = new Timer(2000, radomTrains);
			if(timer.isRunning()) {
				timer.stop();
			}
			else {
				timer.start();	
			}

		}
	};



	/**
	 * Initializes the application with a frame. 
	 * @throws IOException the parsing of the file xml configuration failed.
	 * @throws SAXException the parsing of the file xml configuration failed.
	 * @throws ParserConfigurationException the parsins of the file xml configuration failed.
	 */
	public MetroApplication() throws ParserConfigurationException, SAXException, IOException  {
		initEnv();
		model = null;
		String pathname = loadConfig();

		model = initMetroModel(pathname);
		ConfigurationWindow cw = new ConfigurationWindow(frame, "Line configuration", model);
		ApplicationListenerFactory.setCw(cw);
		
		frame.setSize(1200, 700);
		frame.setExtendedState(JFrame.MAXIMIZED_BOTH);
		frame.setLocationRelativeTo(null);
		frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
		//frame.setJMenuBar(MetroApplicationMenu.getMetroMenuBar(frame,model, toolWindow));
		frame.setJMenuBar(MetroApplicationMenu.getMetroMenuBar(frame,model, ApplicationListenerFactory.toolWindow(frame, model)));
		
		Container contain = frame.getContentPane();
		contain.add(centerPanel(), BorderLayout.CENTER);
		contain.add(westPanel(frame), BorderLayout.WEST);
		ApplicationListenerFactory.getCw().start();
	}

	/**
	 * create a JFileChooser for able user to choose a configuration file for the application
	 * @return pathname of the file
	 */
	private String loadConfig() {
		JFileChooser fileChooser = new JFileChooser();
		fileChooser.setDialogTitle("Choose a xml file to load");
		String path = MetroApplication.class.getResource("../save").getPath();
		fileChooser.setCurrentDirectory(new File(path));
		fileChooser.setVisible(true);
		frame.getContentPane().add(fileChooser);
		int result = fileChooser.showOpenDialog(frame);
		String pathname = null;

		switch (result) {
			case JFileChooser.APPROVE_OPTION:
				pathname = new String(fileChooser.getSelectedFile().getName());
				break;
			case JFileChooser.CANCEL_OPTION:
				pathname = "conf.xml";
				break;
			case JFileChooser.ERROR_OPTION:
				pathname = "conf.xml";
				break;
		}
		return pathname;
	}

	
	/**
	 * create a JFileChooser for able user to save a configuration file for the application
	 * @return pathname of the file
	 */
	private File saveConfig() {
		JFileChooser fileChooser = new JFileChooser();
		fileChooser.setDialogTitle("Choose a xml file to load");
		String path = MetroApplication.class.getResource("../save").getPath();
		fileChooser.setCurrentDirectory(new File(path));
		fileChooser.setVisible(true);
		fileChooser.setSelectedFile(new File("config.xml"));
		frame.getContentPane().add(fileChooser);
		int result = fileChooser.showSaveDialog(frame);
		File file = null;

		switch (result) {
			case JFileChooser.APPROVE_OPTION:
				System.out.println(fileChooser.getSelectedFile().getPath());
				file = new File(fileChooser.getSelectedFile().getPath());
				break;
			case JFileChooser.CANCEL_OPTION:
				//pathname = "conf.xml";
				break;
			case JFileChooser.ERROR_OPTION:
				//pathname = "conf.xml";
				break;
		}
		return file;
	}

	private void initEnv() {
		try {
			UIManager.setLookAndFeel(UIManager.getSystemLookAndFeelClassName());
		} catch (ClassNotFoundException e1) {
			// never append. In worse case the default look and feel is here.
		} catch (InstantiationException e1) {
			System.err.println("Error durring the instantiation of the look and feel");
			e1.printStackTrace();
		} catch (IllegalAccessException e1) {
			System.err.println("Error durring the instantiation of the look and feel");
			e1.printStackTrace();
		} catch (UnsupportedLookAndFeelException e1) {
			// never append. In worse case the default look and feel is here. 
		}		
	}
	
	/**
	 * Initializes the {@link MetroModelImpl} of the application.
	 * @return
	 * @throws IOException the parsing of the file xml configuration failed.
	 * @throws SAXException the parsing of the file xml configuration failed.
	 * @throws ParserConfigurationException the parsins of the file xml configuration failed.
	 */
	private MetroModelImpl initMetroModel(String path) throws ParserConfigurationException, SAXException, IOException {
		MetroModelFactory metroFactory = MetroModelFactory.newInstance(path);
		return metroFactory.getMetroModelImpl();
	}

	private Component westPanel(JFrame frame) {
		JPanel panel = new JPanel(new BorderLayout());
		JTabbedPane tabbedPane = TabbedConfView.getTabbedView(model);
		panel.add(tabbedPane,BorderLayout.NORTH);
		panel.add(createJToolBar(),BorderLayout.CENTER);
		panel.add(InfoPanel.getInfoPanel(model, frame,ApplicationListenerFactory.toolWindow(frame, model)),BorderLayout.SOUTH);
		return panel;
	}

	/**
	 * Build the JToolBar of the programs
	 * @return JToolBar build
	 */
	private JToolBar createJToolBar() {
		JToolBar toolBar = new JToolBar(JToolBar.HORIZONTAL);
		toolBar.setFloatable(false);
		toolBar.setPreferredSize(new Dimension(10, 10));
		toolBar.setMaximumSize(new Dimension(10, 10));

		final JButton startButton = new JButton(GraphicFactory.ICONPLAY);
		startButton.setToolTipText("Launch program");
		startButton.addActionListener(new ActionListener() {	
			@Override
			public void actionPerformed(ActionEvent e) {
				model.start();
				startButton.setEnabled(false);
			}

		});
		toolBar.add(startButton);

		final JButton ramdomButton = new JButton(GraphicFactory.ICONSTAR);
		ramdomButton.setToolTipText("add Trains");
		ramdomButton.addActionListener(addRandomTrains);
		toolBar.add(ramdomButton);

		final JButton toolButton = new JButton(GraphicFactory.ICONTOOL);
		toolButton.setToolTipText("Configuration of lines");
		toolButton.addActionListener(ApplicationListenerFactory.toolWindow(frame, model));
		toolBar.add(toolButton);

		final JButton saveButton = new JButton(GraphicFactory.ICONTOOL);
		saveButton.setToolTipText("Save Configuration");
		saveButton.addActionListener(saveWindow);
		toolBar.add(saveButton);

		JButton aboutButton = new JButton(GraphicFactory.ICONINFO);
		aboutButton.setToolTipText("About");
		aboutButton.addActionListener(aboutWindow);
		toolBar.add(aboutButton);

		JButton exitButton = new JButton(GraphicFactory.ICONEXIT);
		exitButton.setToolTipText("Exit the game");
		exitButton.addActionListener(exitProgram);
		toolBar.add(exitButton);

		return toolBar;
	}

	/**
	 * The Map of the station.
	 * @return the map of the application.
	 */
	private JPanel centerPanel() {
		JPanel panel = new JPanel();
		MetroMap metroMap = new MetroMap(model);
		panel.add(metroMap);
		return panel;
	}


	/**
	 *Sets visible the windows with the game.
	 */
	public void start() {
		//frame.pack();
		frame.setVisible(true);
	}



}
